/*
 * baseOP.cpp
 *
 *  Created on: 30-Oct-2011
 *      Author: willion
 */

#include "baseOP.h"

#include <iostream>
using namespace std;

#include <cstdlib>
#include <errno.h>

//********************** constructor use default seed
//the default seed is 111
baseOP::baseOP(int l_dim, int m_dim, int n_dim, int looptime):
		_l_dim(l_dim), _m_dim(m_dim), _n_dim(n_dim), _looptime(looptime)
		//LEFT(1), RIGHT(2), RESULT(3)
{
	_seed = 111;

	srandom(_seed);

	init_matrix(_left, _l_dim, _m_dim);
	fill_matrix(_left, _l_dim, _m_dim);

	init_matrix(_right , _m_dim, _n_dim);
	fill_matrix(_right , _m_dim, _n_dim);

	init_matrix(_result , _m_dim, _n_dim);
	fill_matrix(_result , _m_dim, _n_dim, false);
}

//*************************** destructor
//destroy and recycle the matrix
baseOP::~baseOP()
{
	// TODO Auto-generated destructor stub

	destroy_matrix(_left, _l_dim, _m_dim);
	destroy_matrix(_right, _m_dim, _n_dim);
	destroy_matrix(_result, _l_dim, _n_dim);
}

//***************************** method baseOP::multi()
//multiply two matrices
// no need to comment
void baseOP::multi_matrix(const int** left, const int** right,
		int** result,
		int l_dim, int m_dim, int n_dim)
{
	int tmp_res = 0;

	for (int i = 0; i < l_dim; i++)
	{
		for (int j = 0; j < n_dim; j++)
		{
			tmp_res = 0;

			for (int k = 0; k < m_dim; k++)
			{
				tmp_res += (left[i][k] * right[k][j]);
			}

			result[i][j] = tmp_res;
		}

	}
}

//*********************** method baseOP::init_matrix()
//random generate the matrix or just fill zero into it
void baseOP::init_matrix(int** &matrix, int l_dim, int m_dim)
{
	int* Parray = new int[l_dim*m_dim];

	if (Parray == NULL)
	{
		cerr <<"insufficient memory" <<endl;
		cerr <<"Terminating" <<endl;

		exit(-ENOMEM);
	}

	//allocate the memory for the matrix
	matrix = new int*[l_dim];

	for (int i = 0; i < l_dim; i++)
	{
		matrix[i] = (Parray + i*m_dim);
	}
}

void baseOP::fill_matrix(int** &matrix, int l_dim, int m_dim, bool rd_gen)
{
	if (rd_gen == true)
	{
		//randomly generate the matrix
		for (int i = 0; i < l_dim; i++)
		{
			for (int j = 0; j < m_dim; j++)
			{
				matrix[i][j] = random();
			}
		}
	}
	else if (rd_gen == false)
	{
		//generate the matrix with 0
		for (int i = 0; i < l_dim; i++)
		{
			for (int j = 0; j < m_dim; j++)
			{
				matrix[i][j] = 0;
			}
		}
	}
}

//************************** method baseOP::destroy_matrix()
void baseOP::destroy_matrix(int** matrix, int l_dim, int m_dim)
{
	//cant be void pointer
	if (matrix == NULL)
	{
		return;
	}

	//recycle the memory
	//no need to comment
	int* Parray = matrix[0];
	delete Parray;

	delete matrix;

	matrix = NULL;
}

//************************** method baseOP::display_matrix()
//just print out the matrix
//nothing worth commenting
void baseOP::display_matrix(const int token)
{
	int** matrix;
	int l_dim = 0;
	int m_dim = 0;

	switch(token)
	{
		case LEFT:
		{
			matrix = _left;

			l_dim = _l_dim;
			m_dim = _m_dim;

			cout <<"--------------left---------------" <<endl;

			break;
		}
		case RIGHT:
		{
			matrix = _right;

			l_dim = _m_dim;
			m_dim = _n_dim;

			cout <<"--------------right---------------" <<endl;

			break;
		}
		case RESULT:
		{
			matrix = _result;

			l_dim = _l_dim;
			m_dim = _n_dim;

			cout <<"--------------result---------------" <<endl;

			break;
		}
		default:
		{
			matrix = _result;

			cout <<"--------------result---------------" <<endl;

			break;
		}
	}

	cout <<endl;

	for (int i = 0; i < l_dim; i++)
	{
		for (int j = 0; j < m_dim; j++)
		{
			cout <<matrix[i][j] <<"\t";
		}

		cout <<endl;
	}

	cout <<endl;
}

//********************* virtual method baseOP::go()
//just a shadow
void baseOP::go(int multi_method)
{

}

//******************* method block:calc_time()
void baseOP::display_time(struct timespec start, struct timespec end)
{
	time_t off_sec = end.tv_sec - start.tv_sec;
	long off_nsec = end.tv_nsec - start.tv_nsec;

	double nsec = 1;

	for (int i = 0; i < 9; i++)
	{
		nsec *= 10;
	}

	nsec *= off_sec;

	nsec += off_nsec;

	nsec /= _looptime;

	cout <<"-------------Time---------------" <<endl;
	cout <<endl <<"time: " <<nsec <<" nsec" <<endl <<endl;;
}

void baseOP::transpose_matrix(int** &matrix, int l_dim, int m_dim)
{

	int** tmp_pointer = NULL;

	init_matrix(tmp_pointer, m_dim, l_dim);

	for (int i = 0; i < l_dim; i++)
	{
		for (int j = 0; j < m_dim; j++)
		{
			tmp_pointer[j][i] = matrix[i][j];
		}
	}

	destroy_matrix(matrix, l_dim, m_dim);

	matrix = tmp_pointer;

}
